//
//  ReadMe.swift
//  test
//
//  Created by HM on 2017/6/28.
//  Copyright © 2017年 itheima. All rights reserved.
//

/*
 
 
    - 第三天
 
        - readMe文件
            - 需要把一些不好理解的 或者是项目核心的东西 通过readMe文件记录
            - 尽快脱离
        - 总结每天学习的知识点
 
 
        - 公司人员分配
            - 甲方
            - 销售
            - 老板
            - 技术总监
                - 项目组
                    - 项目经理
                    - 程序员
                        - 前端开发
                        - 苹果&安卓
                        - 后台
                        - UI
                        - 产品经理
                        - 测试工程师
            - 早会
            - 周会
 
 
        - 项目部署
            - github
            - OSChina
        - HTTPS 需要每次输入用户名和密码 如果代码多可能会导致上传不成功
        - SSH
            - 客户端生成rsa 公钥 和 私钥 rsa(非对称加密 效率底)
            - 公钥给服务器
            - 每次上传代码的时候 客户端会自动生成AES密钥
            - 通过AES给代码加密(AES是对称 效率高)
            - 使用私钥给AES加密 然后传到服务器
            - 用公钥把加密后的AES解密
            - 通过解密后的AES把代码解密
            - 保存代码到服务器
 
        - 第三天回顾
            - 在远程仓库创建项目
                - 名称
                - 语言
                - 忽略不能设置 不支持Swift
                - 设置证书
            - 配置公钥
            - 把项目克隆到本地
            - 提交忽略文件
            - 创建项目
            
            - MVVM
                - M model
                - V (view & viewController)
                - VM (viewModel)帮助上面的V做事情
            - 设置项目相关设置
                - 最低支持版本
                - 横竖屏
                - 启动图 & icon
                - 类前缀
            - 采用纯手写代码方式开发
            - 首页 消息 发现 我 主控制器
            - 主控制器 四个导航控制器 每个导航控制器中 一个ViewController
            - 抽取一个添加字控制器的公共方法
 
 
        - 第四天
            - 导航栏的按钮
                - 样式:
                    - 图片
                    - 文字
                    - 图片 + 文字
 
            - 第四天上午内容回顾
                - 自定义tabBar
                    - 添加撰写按钮 设置center.x 和y
                    - 撰写按钮添加监听方法 
                    - 通过协议代理 和闭包完成监听事件回调
                        - NSObjectProtocol 一定要遵守基协议
                        - 声明代理需要使用weak 修饰
                - 通过在layoutSubviews 来遍历其tabbar subviews 子控件
                    - UITabBarButton 这个按钮 设置 x 和 宽度
                    - NSClassFromString 完成字符串 转 AnyClass
                - 自定义UIBarButtonItem
                    - 便利构造函数
                    - 传入参数  imgName tilte target action imgName 和 title 有一个可能为nil
                - 设置导航按钮
                - 自定义TempVc 完成二级以及下面的界面的push跳转
                - 自定义导航控制器
                    - 重写push 方法 监听 后 完成 左侧按钮的文字显示
                    - 重写设置interactivePopGestureRecognizer 才可以点击边缘可以pop返回
                    - 实现gestureRecognizerShouldBegin代理方法 解决一级界面手势bug
                - 自定义VisitorView 
                - 抽取RGB 颜色 和 随机颜色
 
                - 第四天下午内容回顾
                    - 自定义VisitorView -> (四个控制器显示的效果差不多 所以需要抽取)
                    - 一共有多少个控件(圆圈(首页) 遮挡 logo 文字 两个按钮)
                    - 抽取出baseVc基类 在类里面添加一个属性为VisitorView
                        - 定义一个属性 bool 是否登录 -> isLogin 全局
                        - loadView 中判断用户是否登录
                            - 如果登录了 角系统自己创建一个self.view
                            - 反之 view = visitorView
                    - 按照不同的控制器来完成不同的logo和文字的显示
                        - 不同的logo 和文字 它是visitorView的属性 只有visitorView 可以设置它们
                        - 需要在visitorView提供一个方法 供外接的visitorView调用
                            - 在外面还需要知道是哪个控制器(如果是首页的话 需要设置圆圈动画 其它的控制器 需要隐藏圆圈) -> 可选值来判断那个控制器
                    - 在visitorView给圆圈imageView设置核心动画
                    - 抽取extension 和 common公共方法和属性
 
 
 
        - 第五天上午内容回顾
            - 回顾OC的单例写法
            - 单例的特点和作用
                - 特点: 全局只有一个 唯一性 只创建一次 和app一起销毁
                - 对一些使用率比较高的类 对他使用单例 防止重复创建 对第三方框架进行封装 和项目进行隔离
                - 注意: 项目中不能什么地方都使用单例
            - 学习Swift中单例的定义
                - 和Swift中懒加载写法相似
                    - static let 名字: 类型 = 类型()
                    - static let 名字: 类型 = {return 对象}()
            - OC的项目中使用Swift定义的类
                - 注意: 
                    - 需要在OC的类中进行import
                    - 项目名中如果有中文和其他特殊符号 可能导致 找不到当前的Swift类
                    - 需要更改product name 
            - Swift项目中使用OC定义的类
                - 需要创建一个桥接文件(xx.h文件)
                - 如果你当前项目首次使用OC文件 如果直接拖入项目中 系统将不在提示创建桥接文件
                - 如果你不点击创建 也会错过 需要程序员手动创建 而且还需要手动设置桥接文件的路径
                - 在Swift中使用OC的类 需要在桥接文件中引入
            - OC-AFN的网络封装
                - 构造一个单例类
                - 继承afhttpsessionManger
                - 主要的是实现两个请求方法(get & post)
                - 封装一个公共方法 同时支持get&post请求
                - 对每个接口在进行一次封装 (叫当前的工具类提供请求方式和对每个接口进一步封装 -> 便于网络接口管理)
            - Swift-AFN的网络封装
                - 同上
            - Pods的移除
 
 
        - 第五天下午
            - OAuth授权
                - 自己开发的app
                    - (客户端)注册界面 -> 用户名和密码和验证码
                - 短信验证:
                    - 第三方: 需要收费
                        - 提供一个网址 完成注册和登录 充值 它会提供一个sdk
                        - sdk   
                            - 对象
                                - 发送验证码 -> 手机号 & 标识(公司标识) -> 验证码返回1234
                                - 校验验证码 手机号(1234)和短信得到的 校验是否相等
 
                - 如果后期可以正常的使用服务器的数据 
                    - 注册
                    - 登录 -> 通过手机号和密码 服务器会给你一个token123456789 唯一标识(人的身份证)
                    - 获取数据(鉴权接口(张三才可以访问自己的信息-> 手机号 和密码))
 
 
            - OAuth open auth 开发的授权
                - 目的:
                    - 开发一个山寨微博 但是需要使用新浪微博的接口
                    - 如果使用新浪微博的接口 就需要遵守人家提出来的协议
                    - 需要登录www.open.weibo.com
                    - 注册一个微博账号
                    - 成为开发者
                        - 个人
                        - 公司 
                    - 注册应用-> 山寨微博-> 标识
                        - appkey
                        - appsecret
                        - 回调页
                    - 加载微博提供的授权界面
                        - 得到授权码(code)
                    - 通过新浪微博提供的接口 和code 得到对应的token
                    - 通过得到的token 获取 新浪微博提供的接口数据
                    - 注意: 在开发测试阶段需要开发者配置测试账号 未发布期间 只有相关的测试账号才可以访问微博的数据
 
 
 
        - 第五天下午回顾
            - 添加文件夹 -> OAuthVC
                - 搭建OAuthVc的界面 -> 导航控制器 左侧按钮 右侧 中间标题
                - 通过模态形式弹出的控制器
                - 集成了一个WebView
                - 通过设置webView 的代理 拦截url请求 和字符串的截图获取code
                - 通过code 和 新浪微博提供的接口 获取到token
                - 通过token 和uid 得到用户信息的数据
                - KVC字典转模型 而且为了叫模型上的属性都有值 需要手动赋值screen_name avatar_large
 
 
 
 
        - 第六天
            - 第六天上午内容
                - UserAccountModel 继承 NSCoding协议
                    - 实现encode  initWithCoder 方法 进行(二进制和数据转换)
                - OAuthVc中实现两个方法 保存 和 获取 对象方法
                - 在网络请求工具类中抽取OAuthVc的两个网络请求
                - 创建OAuthViewModel 
                    - 帮助控制器请求数据
                    - 帮助控制器保存数据 和 获取数据
                    - 构造成单例
                    - 提供userAccountModel 
                        - 供其它界面使用里面的数据方便
                        - 避免多次操作沙盒(因为读取内存的数据 要比沙盒的数据块)
                            - 需要userAccountModel在init方法中赋值操作 -> 单例引起
                            - 在保存userAccountModel方法中需要手动赋值 避免第一次创建userAccountModel为nil的bug
                    - 提供一个AccessToken属性供外界使用
                        - 如果没有保存过数据 应该返回nil
                        - 如果保存了
                            - 判断是否过期 如果没有过期 直接返回
                            - 如果过期了 返回 nil
 
            - 关于app的根控制器的选择
                - 标识 -> 判断用户是否登录 isLogin
                    - 如果登录 -> RootVc = WelcomeVc -> HMainVc(登录状态的)
                    - 如果没有登录 -> RootVc = HMainVc(访客视图) -> OAuthVC -> WelcomeVC -> HMMainVc(登录状态)

            - 第六天下午内容总结
                - OAuthViewModel中
                    - 定义一个isLogin 属性 判断用户是否登录
                        - 标识 -> token (判断它是否存在)
                - 开发欢迎界面
                    - vc
                        - bgImageView 头像 文字
                    - 设置动画 -> 动画
                        - viewdidAppear 实现动画
                        - 阻尼动画
                            - 因为是更改了头像的顶部约束 需要手动调用self.view.layoutIfNeed 方法刷新界面
                - 分析首次登录app根控制器的选择
                    - 登录 -> welComeVc
                    - 反之 -> MainVC(访客视图)
                - 使用通知切换根控制器
                    - oauthVC -> 告知appdelegate 切换为rootVC = welComeVc
                    - welComeVc -> 告知appdelegate 切换为rootVC = MainVC(登录后)
                    - 利用通知的object来区分是哪个控制器发送的通知(使用一个通知名完成)
                - 开发微博登录状态的字控制器界面
                    - baseVc view -> tableView
                - 通过首页微博接口请求数据
                    - 使用yymodel 完成字典数组转模型数组
                - 在homeVc设置数据源代理 完成tableView基本数据显示
 
 
 *****************************************************************************************************
 
        - 第七天
            - 首页cell布局分析
                - 一共分为三部分
                    - 原创微博
                        - 头像
                        - 昵称
                        - 等级
                        - 时间
                        - 来源
                        - 认证
                        - 正文
                        - 配图(?)
                    - 转发微博(?)
                        - 正文
                        - 配图(?)
                    - 底部视图
                        - 分为三部分按钮
                        - 转发 评论 赞
 
 
            - 第七天上午内容回顾
                - 首页cell进行分析
                - 自定义首页cell
                - 自定义原创微博view
                    - 目前还没有引入配图
                    - 原创微博的底部 == 微博正文的底部
                - 采用MVC模型是给cell赋值
                    - 弊端: 关于原创微博里面显示的图片的业务逻辑处理需要在originalView
                - 采用的是MVVM模式
                    - 创建一个statusViewModel -> 为谁服务 -> 首页cell(原创 转发 底部视图)服务
                - 需要使用statusViewModel做数据传递
                    - 分析: 数据的传递过程
                        - 控制器(dataList(数组)) -> homecell(每个数组的元素) -> (分别给原创 转发 底部视图)
                    - 采用MVC时候 数组中的类型 -> HomeModel (数据业务逻辑放在了viewModel中)
                - 需要构造一个数组 -> 类型是statusViewModel (把homeModel作为statusViewModel的属性)
                - 从网络获取回来的数据 它是字典数组 通过yymodel 得到是homeModel数组
                - 需要循环homeModel数组 -> 循环一次对应创建一个statusViewModel 接着给statusViewModel的属性HomeModel赋值 -> 使用一个临时数组保存每次循环创建的 statusViewModel
                - statusViewModel 做处理
                    - 添加属性verifiedImage 通过该属性给可以直接给原创微博的控件赋值
                        - verifiedImage 得到的业务逻辑处理statusViewModel
                        - homeVc -> homeCell -> 三个子控件(原创微博 底部 转发)
                        - 为什么传递statusViewModel 而不传HomeModel
                - 首页的网络请求抽取到HMNetworkTools中
                - 把首页的网络请求抽取到homeViewModel中
                    - homeViewModel作用(dataList)
                        - 帮助首页请求数据
                        - 处理数据
                        - 保存数据
                        - 为首页提供数据
                        - 告知首页以上事情是否完成的结果
 
 
            - 第七天下午内容
                - 处理原创微博的会员等级-> statusViewModel中处理
                - 原创微博的其他控件赋值
                - 自定义底部视图(三个按钮 平均分配布局)
                - 假设没有转发微博 对cell进行布局 (使用tableView自动计算行高)
                - 假设有转发微博开始开发UI
                - 在HomeModel中添加属性retweeted_status 
                - retweeted_status 通过它是否有值来判断是否显示转发微博和赋值操作
                - 自定义配图控件-> collecitonView 完成
                - 在HomeModel中添加属性pic_urls 
                - pic_urls是否有值 而且大于 0 来判断是否显示配图
                - 在PictureView中得到pic_urls这个数组来计算PictureView的实际size 从而更新约束
 
 
 
 ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* *********
 
 
    - 第八天
        - 单张图片显示
            - 如果是单张图片
                - 我们的pictureView的size 和itemSize是通过网络的单张图片来决定他的size
                - 但是如果想使用image 的宽和高 就必须下载到本地 才可以使用
                - 解决该问题 
                    - 什么时候下载单张图片
        - 第八天上午内容回顾
            - 自定义PictureView 
                - 设置itemSize 和间距(垂直 水平)
                - 设置代理
            - 自定义PictureViewCell
                - 添加里面的控件 bgImageView
                    - 设置图片填充方式
                    - 赋值
            - 给转发微博添加配图控件
                - 通过返回来的转发微博数据决定配图是否显示和重新设置约束
            - 对首页的cell的一些细节进行处理
                - 分割线
                - 背景颜色的选择
                - cell选中样式
            - 单张图片为什么下载的原因
            - 介绍调度组和调度组在Swift中的使用
 
 
        - 关于下载单张图片下载
            - 什么条件下下载(什么样的数据)pic_urls.count == 1
                - homeModel -> pic_urls (原创微博)
                - retweeted_status -> pic_urls (转发微博)
 
        - 企业开发上拉加载更多和下拉刷新实现逻辑
                - 请求参数中有两个参数 
                    - pageCount(页数) (默认可能是0 )
                    - pageSize(每次请求数据的条数)(默认值20 如果你想自定义 pageSize = 10)
 
                    - 下拉刷新
                        - 保存网络数据的数组清空
                        - pageCount = 0
                        - pageSize = 10
                    - 上拉加载更多
                        - 把这次请求回来的数据拼接到当前这个数组的后面
                        - pageCount ++ 
                        - pageCount = 1
                        - pageSize = 10
                    - 一旦触发下拉刷新数据全部清空 pageCount = 0 pageSize = 10
 
        - 分析如何自定义下拉刷新控件
            - 自定义 -> 继承谁 -> UIControl
            - 放到谁身上? tableView身上 (y坐标 = - 控件高度)
 
        - 第八天下午内容总结
            - 单张图片缓存
                - 调度组
                - 需要在网络请求得到数据转模型后
                - 通过遍历模型中
                    - 判断如果是原创微博 且pic_urls.count == 1
                    - 判断如果是转发微博 且pic_urls.count == 1
                        - 使用sdwebImage下载图片
                - 通过调度组监听下载图片完成 然后执行闭包finish(true)
 
                - 在PictureView中
                    - dealPictureViewSize中
                        - 判断count == 1
                        - 通过原创微博或者转发微博给配图提供的图片数组的first得到这个图片的地址
                        - 通过地址得到本地保存的图片
                        - 按照业务需求 提出一个80  150 图片处理
                        - 得到最终的图片size 设置给配图size
                        - 分别设置配图的itemSize
                            - 单张图片的itemSize == image.size
                            - 多张图片 itemSize == cellWH
                - 自定义上拉加载更多
                    - 监听cell滚动到最后一行发送请求请求数据
                - since_id(下拉刷新) max_id(上拉加载更多)
                    - 需要在NetworkTools中添加参数
                    - 要使用Int64为 默认Int 不满足需求
                    - HomeViewModel中需要把请求数据方法添加参数 isPullUp
                    - 如果是下拉刷新 请求回来的数据放在原数据的前面
                    - 如果是上拉加载更多 请求回来的数据放在原数据的后面
                - 使用UIRefreshControl来完成下拉刷新
                - 自定义HMRefreshControl控件
 
 ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* *********
 
    - 第九天上午内容总结
        - 在HMRefreshControl中重写以后的方法 willmovetosuperView
            - 得到tableView对象
            - 使用KVO来监听tableView 的contentOffSet变化
            - 在KVO中得到tableView的contentOffSet变化
                - 通过临界值设置不同的控件属性(正常 下拉中 刷新中)
                - 定义了一个全局属性记录下拉刷新控件的状态hmType
                - 使用didSet 监听hmType变化设置文字的text 和 箭头 和 菊花的变化
                - 正常中
                    - 如果oldValue == refreshing .contentInset.top -= 50
                        - 显示箭头
                        - 停止菊花动画
                    - 其它 改变箭头的方向
                - 下拉中
                    - 改变箭头的方向
                - 刷新中
                    - 隐藏箭头
                    - 开启菊花动画
                    - 发送action告知外界刷新
                - 定义一个方法定制动画
                - 把自定义控件集成到微博项目中
        - 原创微博 微博时间处理
            - 判断是否是今年发布的微博
 
 
 
        - 把首页的cell中的gif图片标识加上(使用字符串后缀是否是.gif)
        - pulldownTipLabel (显示? -> 首页 和下拉刷新显示)
            - 如何实现的判断footerView是否动画
            - 把pulldownTipLabel 放在nav.view 上 nav.bar下面
            - 解决多次动画bug -> 根据pulldownTipLabel是否隐藏
        - 撰写按钮点击弹出view -> composeView -> 类方法完成弹出
        - 自定义按钮(需要自己更改imageView 和titleLabel的frame完成)
 
 
  ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* *********
        
        第十天上午内容回顾
            - 读取本地plist文件 得到数组 然后 使用yymodel 字典转模型数组
            - 给6个按钮设置放大和缩小动画
                - 在创建6个按钮后 需要把6个按钮保存起来 便于我们给6个按钮设置动画
            - 学习使用第三方框架 pop -facebook提出
                - 使用弹簧动画
                - 设置动画 显示动画  移除的动画
                    - show() 显示动画
                    - 点击屏幕时候 设置移除动画
                - 把动画加载谁身上 view动画 center
                - +-350 6个按钮倒序
            - 给HMComposeButton添加属性 composeModel 便于我们使用其里面的className 直接就可以不用tag
 
         第十天下午内容回顾
            - 通过字符串获取class 创建对象 指定类型为 类型名.type
            - 自定义发布微博界面
                - 导航栏左右侧按钮按钮
                - 自定义titleView -> 富文本
                - 自定义右侧按钮
                - 自定义textView
                    - 设置代理监听文字改变右侧按钮状态
                    - 添加占位文字
                    - 重写font属性设置文字font
                    - 添加placeholder给占位文字设置text
                    - 通过监听系统通知uitextViewDidChange 来显示和隐藏占位文字
                - 自定义bottomView
                    - 添加5个按钮
                    - 监听按钮点击使用闭包事件回调(有参数闭包 为枚举)
                    - 通过枚举名得到枚举值 rawValue
                    - 通过枚举值得到枚举名 枚举类型(rawValue:Int)
                - 自定义PictureView
                    - 添加在textView身上
                - 自定义PictureViewCell
 
 
 ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* ****
        第十一天
            - 底部视图的第四个按钮
                - 首次的时候显示的是笑脸 点击后 键盘变为表情键盘 按钮图片变成键盘
                - 如果是键盘按钮 点击后 键盘变为系统键盘 按钮图片变为表情
 
 
        第十一天上午内容回顾
            - 通过UIImagepickerController 打开相册获取image
            - 把获取到的image 提供给配图(pictureView)
            - pictureView把外接提供的图片使用数组进行保存
            - 把保存后的图片提供给每个cell
            - 自定义cell中的背景图片 然后完成赋值(image)
            - 如果当前显示是0张图片或者是9张不会显示加号图片
                - 反之显示加号图片 所以说需要多加一个items
                - 当判断item和imageList.count 相等的时候 就可以认为是加号图片
                - 设置加号cell的高亮效果
                - 反之其它高亮设置为nil
                - 点击加号图片cell 一样可以打开相册(使用的是闭包完成)
            - 给cell中每个按钮添加删除按钮
                - 点击删除按钮使用闭包告知父类删除imageList中指定的元素
            - 对当前发布微博界面细节优化
                - 背景颜色的选择
                - 配图显示和隐藏的业务逻辑
            - 监听系统通知 监听键盘frame将要改变更新底部视图的底部约束设置动画
            - 自定义表情键盘(设置表情键盘是通过textView.inputView)
                - 如何判断是否是系统键盘和自定义表情键盘(inputView是否为nil)
                - 通过inputView是否为nil 来设置底部视图的emoticonButton按钮的图片
 
        第十一天下午内容
            - 自定义键盘中的底部视图
                - 使用UIStackView (布局方式 填充方式)
                - 通过闭包把点击按钮事件回调
                - 设置默认选中的按钮
            - 自定义表情配图
                - 设置itemSize 和 垂直和水平间距
            - 自定义UIEmoticonPictureViewCell
                - 添加messageLabel
            - 读取bundle文件里面的数据
                - 获取bundle后分别读取 default emoji lxh里面的info.plist文件 字典数组转模型数组
                - 通过一维数组 使用OC数组截取获取二维数组
 
 
  ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* ****
 
    - 第十二天上午内容回顾
        - 二维数组构造成三维数组
        - 给pageView提供数据
        - 给pageView设置代理 监听pageView.contentOffSet.x变化
            - 通过contentOffSet.x + 屏幕一半 获取到底那个cell显示的更过
            - 通过得到显示多的cell这个对象 获取对应的IndexPath
            - 通过IndexPath.section 获取对应的底部视图中的按钮 设置其选中状态
        - 给PageViewCell中添加20个表情按钮
            - 给PageViewCell提供数据 -> 一维数组(emoticons[HMEmoticonModel])
            - 通过遍历外界给的一位数组
            - 通过下标给每个按钮赋值
                - 判断是emoji表情 -> title
                - 还是图片表情 -> image
            - 给PageViewCell中添加删除按钮
        - 监听底部视图按钮点击 角pageView 滚动到指定组和页
        - 添加pageControl 按照逻辑来切换pageControl的显示
            - 两个只读计算型属性(而在xcode8 以后不能看到)
            - currentPageImage  pageImage
            - 通过kvc进行赋值
 
 
    - 第十二天下午内容回顾
        - 监听20个表情按钮点击发送通知告知控制器(composeVc)
            - 自定义表情按钮
                - 给其添加模型属性
            - 通过发送通知object 传递到接收通知方
            - 判断它是emoji还是图片表情
                - 如果是emoji insert 完成
                - 如果是图片表情 
                    - 通过路径获取image
                    - 通过创建文本附件 设置image  bouce
                    - 通过文本附件得到对应的不可变富文本
                    - 通过总得可变富文本替换对应位置的不可变富文本
                - 程序员发送系统通知
                - 程序员使用系统代理完成协议方法执行
            - 通过点击表情键盘中的删除按钮告知textView删除文字或者图片
            - 当点击20个表情按钮需要保存模型数据 为最近表情提供数据
                - 通过yymodel完成归档和解档
                    - 需要重写init方法
            - 发送文字微博
            - 发送图片微博
                - 使用表单形式提交数据到服务器
            - 发送带有图片的微博 需要得到图片对应的图片描述字符串发布 不是直接发布图片
        
 
 
********* ********* ********* ********* ********* ********* ********* ********* ********* ********* ****
 
    - 第十三天上午回顾
        - 学习正则的常用使用规则
        - 使用正则遍历微博正文文字中的图片描述 从而获取对应的图片的png(allPath)
        - 通过allPath得到对应的image
        - 通过yy_text 传入image 和fontSize 获取可变富文本
        - 通过正则得到匹配结果集合数组遍历 获取每个匹配到的元素的范围 进行替换
        - 在返回最终的富文本前需要在通过正则匹配@xx #xx# http:www.baidu.com
        - 在显示图文混排的UI 要把uilable 替换为 yylabel
        - 如果当前富文本中包含中文英文emoji 和图片 可能需要设置自定义行高
        - 可以设置点击高亮位置文字的高亮监听方法 从而接收事件左自己特有的事情
 
    - 在新浪微博如何使用FMDB
        - 创建一个数据库
            - 创建一张表
                - 创建多少个属性?
                    - statusid(微博id) (主键 不能为空)
                    - userid(用户id 防止其他人登录你的微博app页可以拿到你的缓存数据) (主键 不能为空)
                    - status (微博数据字典) 转成二进制
                    - createtime (保存数据的时间)
 
                - 选中createtime字段 在default 后面添加 (datetime('now','localtime')) 告知数据库保存数据的时候 记录下保存时间
 
 
 
 
 
 */
